package com.erp.erp_ui.warehouse.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.erp.enums.*;
import com.erp.erp_entitys.business.entity.CarryDetailProductEntity;
import com.erp.erp_entitys.business.req.ImportCarryDetailInfoReq;
import com.erp.erp_entitys.business.rsp.ImportCarryDetailRsp;
import com.erp.erp_entitys.warehouse.entity.*;
import com.erp.erp_entitys.warehouse.req.PlanInStoreListReq;
import com.erp.erp_entitys.warehouse.req.PlanInStoreStatistics1Req;
import com.erp.erp_entitys.warehouse.rsp.*;
import com.erp.erp_servers.business.ICarryDetailProductService;
import com.erp.erp_servers.business.ICarryDetailService;
import com.erp.erp_servers.warehouse.*;
import com.erp.erp_ui.business.service.CarryDetailService;
import com.erp.erp_ui.money.req.OperationReq;
import com.erp.erp_ui.warehouse.enums.DataIsValidEnum;
import com.erp.erp_ui.warehouse.enums.DataSourceTitleEnum;
import com.erp.erp_ui.warehouse.req.*;
import com.erp.erp_ui.warehouse.vo.*;
import com.erp.utils.DateUtils;
import com.erp.utils.R;
import com.erp.utils.ResultStatusEnum;
import com.erp.utils.StringUtil;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName : PlanInstoreService
 * @Description : 备货入库业务逻辑层
 * @Author : lst
 * @Date: 2020-07-01 18:29
 */
@Service
public class PlanInstoreService {

    /**
     * 日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CarryDetailService.class);

    /**
     * 备货入库接口
     */
    private final IPlanInstoreService planInstoreService;

    /**
     * 备货入库产品接口
     */
    private final IPlanInstoreProductService planInstoreProductService;

    /**
     * 库存接口
     */
    private final IStockService stockService;

    /**
     * 库存明细接口
     */
    private final IStockDetailService stockDetailService;

    /**
     * 出运明细接口
     */
    private final ICarryDetailService carryDetailService;

    /**
     * 出运明细产品接口
     */
    private final ICarryDetailProductService carryDetailProductService;

    /**
     * 附件接口
     */
    private final IAnnexService annexService;

    /**
     * 临时附件接口
     */
    private final ITempAnnexService tempAnnexService;

    @Autowired
    public PlanInstoreService(IPlanInstoreService planInstoreService,
                              IPlanInstoreProductService planInstoreProductService,
                              IStockService stockService,
                              IStockDetailService stockDetailService,
                              ICarryDetailService carryDetailService,
                              ICarryDetailProductService carryDetailProductService,
                              IAnnexService annexService,
                              ITempAnnexService tempAnnexService) {
        this.planInstoreService = planInstoreService;
        this.planInstoreProductService = planInstoreProductService;
        this.stockService = stockService;
        this.stockDetailService = stockDetailService;
        this.carryDetailService = carryDetailService;
        this.carryDetailProductService = carryDetailProductService;
        this.annexService = annexService;
        this.tempAnnexService = tempAnnexService;
    }

    /**
     * 备货入库-首页-分页查询
     * @param req 查询条件
     * @return 分页结果
     */
    public PageInfo<PlanInStorePageListVo> getListByPage(PlanInStorePageListReq req){
        //初始化查询条件
        PlanInStoreListReq pageReq = new PlanInStoreListReq();
        //赋值
        BeanUtils.copyProperties(req, pageReq);
        //调用接口获取查询结果
        List<PlanInStorePageLisRsp> otherOutStocks = planInstoreService.getListByPage(pageReq);
        //获取分页信息
        PageInfo pageInfo = new PageInfo(otherOutStocks);
        //初始化回参集合
        List<PlanInStorePageListVo> pageVos = new ArrayList<>();
        if(CollectionUtils.isEmpty(otherOutStocks)){
            pageInfo.setList(pageVos);
            return pageInfo;
        }
        for(PlanInStorePageLisRsp other : otherOutStocks){
            PlanInStorePageListVo pageVo = new PlanInStorePageListVo();
            BeanUtils.copyProperties(other, pageVo);
            //日期转换
            pageVo.setTime(DateUtils.format(other.getTime(), DateUtils.DATE_PATTERN));
            pageVo.setCreateTime(DateUtils.format(other.getCreateTime(), DateUtils.DATE_PATTERN));
            //状态转换
            pageVo.setStatusStr(OperationStatusEnum.getDescById(other.getStatus()));

            pageVos.add(pageVo);
        }
        pageInfo.setList(pageVos);
        return pageInfo;
    }


    /**
     * 备货入库-导出运明细分页查询
     * @param req 查询条件
     * @return 分页信息
     */
    public PageInfo<ImportCarryDetailVo> getCarryDetailInfo(ImportCarryDetailReq req){
        //初始化回参对象集合
        List<ImportCarryDetailVo> detailVos = new ArrayList<>();
        //初始化查询对象
        ImportCarryDetailInfoReq infoReq = new ImportCarryDetailInfoReq();
        //字段赋值
        BeanUtils.copyProperties(req, infoReq);
        //调用接口查询结果
        List<ImportCarryDetailRsp> detailRspList = carryDetailService.getCarryDetailInfo(infoReq);
        //获取分页信息
        PageInfo pageInfo = new PageInfo(detailRspList);
        if(CollectionUtils.isEmpty(detailRspList)){
            pageInfo.setList(detailVos);
            return pageInfo;
        }
        for(ImportCarryDetailRsp detailRsp : detailRspList){
            //初始化回参对象
            ImportCarryDetailVo detailVo = new ImportCarryDetailVo();
            //字段赋值
            BeanUtils.copyProperties(detailRsp, detailVo);
            //设置出运明细id
            detailVo.setCarryDetailId(detailRsp.getId());
            //日期处理
            detailVo.setCarryDate(DateUtils.format(detailRsp.getCarryDate(), DateUtils.DATE_PATTERN));
            detailVo.setCreateDate(DateUtils.format(detailRsp.getCreateDate(), DateUtils.DATE_PATTERN));

            detailVos.add(detailVo);
        }
        pageInfo.setList(detailVos);
        return pageInfo;
    }

    /**
     * 根据出运明细id获取出运明细产品信息
     * @param id 出运明细id
     * @return 出运明细产品信息
     */
    public PageInfo<ImportCarryDetailProductVo> getCarryDetailProductList(Integer id){
        //初始化回参对象集合
        List<ImportCarryDetailProductVo> productVos = new ArrayList<>();
        if(null == id){
            return null;
        }
        //调用接口获取出运明细产品信息
        List<CarryDetailInfoRsp> productList = carryDetailProductService.getCarryDetailProductList(id);
        //获取分页信息
        PageInfo pageInfo = new PageInfo(productList);

        if(CollectionUtils.isEmpty(productList)){
            pageInfo.setList(productVos);
            return pageInfo;
        }
        for(CarryDetailInfoRsp product : productList){
            //初始化回参对象实体
            ImportCarryDetailProductVo productVo = new ImportCarryDetailProductVo();
            //字段赋值
            BeanUtils.copyProperties(product, productVo);
            //设置主键id
            productVo.setCarryDetailProductId(product.getId());
            //产品信息
            productVo.setProductCname(product.getProductCname());
            productVo.setProductEname(product.getProductEname());
            productVo.setProductCdesc(product.getProductCdesc());
            productVo.setProductEdesc(product.getProductEdesc());
            //供应商编码
            productVo.setSupplierCode(product.getSupplierId());
            //外币单价
            productVo.setForeignCurrencyUnitPrice(product.getFcUnitPrice());
            //单位
            productVo.setProductUnit(product.getProductUnitName());
            //设置规格编码
            productVo.setSpecificationCode(product.getSpecNo());
            //设置出运明细id
            productVo.setCarryDetailId(id);
            //设置合同类型，默认待定
            productVo.setContractType(ContractTypeEnum.TO_BE_DETERMINED.getId());
            productVo.setContractTypeStr(ContractTypeEnum.TO_BE_DETERMINED.getDesc());
            //设置规说明
            productVo.setSpecificationExplanation(product.getProductSpecExplanation());
            //设置旧仓库名称
            productVo.setWarehouseId(product.getWarehouseCode());
            //设置新仓库默认等于旧仓库
            productVo.setNewWarehouseId(product.getWarehouseCode());
            productVo.setNewWarehouseName(product.getWarehouseName());
            //设置参考数量(产品剩余数量默认等于产品数量,需要减去已被调用数量)
            //产品数量
            BigDecimal productNum = new BigDecimal("0");
            if(StringUtil.isNotEmpty(product.getProductNum())){
                productNum = product.getProductNum();
            }
            //已被调用数量
            BigDecimal num = new BigDecimal("0");
            if(StringUtil.isNotEmpty(product.getNum())){
                num = product.getNum();
            }
            BigDecimal lastNum = productNum.subtract(num);
            //需要减去已被调用数量
            productVo.setReferenceQuantity(lastNum);
            productVo.setNum(lastNum);
            //设置金额小计=单价*参考数量
            productVo.setMoneySubtotal(new BigDecimal("0"));
            //分摊费用单价(默认为零)
            productVo.setShareCostPrice(new BigDecimal("0"));
            //配件成本
            BigDecimal accessoriesCost = new BigDecimal("0");
            if(StringUtil.isNotEmpty(product.getAccessoriesCost())){
                accessoriesCost = product.getAccessoriesCost();
            }
            //成品成本
            BigDecimal finishedProductCost = new BigDecimal("0");
            if(StringUtil.isNotEmpty(product.getFinishedProductCost())){
                finishedProductCost = product.getFinishedProductCost();
            }
            //设置入库成本(配件成本+成品成本)
            productVo.setInstoreCost(accessoriesCost.add(finishedProductCost));
            //批次号:出运明细发票号-采购单号
            String lotNo = product.getCarryDetailNo() + "-" + (StringUtils.isEmpty(product.getPurchaseNo()) ? "" : product.getPurchaseNo());
            productVo.setLotNo(lotNo);
            productVos.add(productVo);
        }
        pageInfo.setList(productVos);
        return pageInfo;
    }

    /**
     * 设置仓库信息
     * @param warehouseInfos 仓库信息集合
     * @param warehouseId 仓库编码
     */
    private String setWarehouse(List<DictionaryInfoRsp> warehouseInfos, String warehouseId){
        if(CollectionUtils.isEmpty(warehouseInfos) || StringUtils.isBlank(warehouseId)){
            return null;
        }
        for(DictionaryInfoRsp warehouseInfo : warehouseInfos){
            if(warehouseInfo.getCode().equals(warehouseId)){
                return warehouseInfo.getName();
            }
        }
        return null;
    }

    /**
     * 备货入库新增
     * @param req 新增参数实体
     * @param creator 创建人
     * @param createNo 创建人编码
     * @return 新增结果
     */
    @Transactional(rollbackFor = Exception.class)
    public R add(PlanInStoreReq req, String creator, String createNo){
        boolean billNoCheckFlag = (null != req.getId() && req.getBillNo().equals(req.getNewBillNo()));
        if(!billNoCheckFlag){
            //单号做唯一校验
            boolean billNoFlag = checkRepeatBillNo(req.getBillNo());
            if(!billNoFlag){
                return R.buildError(ResultStatusEnum.BILL_NO_REPEAT);
            }
        }
        if(!CollectionUtils.isEmpty(req.getDetails())){
            //校验出库数量是否小于等于实际数量（true:是 false:否）
            if(!checkInStockQuantity(req.getDetails())){
                return R.buildError(ResultStatusEnum.IN_STOCK_QUANTITY_CHECK_ERROR);
            }
        }
        //第一步：主表新增、修改
        Integer id = addOrUpdatePlanInStore(req, creator, createNo);
        if(null == id){
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }

        //第二部：备货入库明细新增以及更新出运明细剩余数量
        insertDetail(req, id, creator, createNo);

        //第三步：添加附件信息
        boolean flag = addAnnex(req.getAnnexList(), id, creator, createNo);
        if(!flag){
            LOGGER.info("仓库管理-其它出库-批量新增附件异常");
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }
        //第四步：删除临时附件信息
        deleteTempAnnex(req.getAnnexList());

        return R.build(ResultStatusEnum.SUCCESS);
    }

    /**
     * 批量处理临时附件信息，将临时附件设置为失效
     * @param annexReqs
     */
    private void deleteTempAnnex(List<AnnexReq> annexReqs){
        //没有附件
        if(CollectionUtils.isEmpty(annexReqs)){
            return;
        }
        //存在附件
        for(AnnexReq annex : annexReqs){
            if(null != annex.getNews()){
                //旧附件,不用修改
                continue;
            }
            TempAnnexEntity tempAnnex = new TempAnnexEntity();
            //设置临时附件id
            tempAnnex.setId(annex.getId());
            //设置修改时间
            tempAnnex.setUpdateTime(new Date());
            //将附件设置为失效
            tempAnnex.setValid(0);
            tempAnnexService.update(tempAnnex);
        }

    }

    /**
     * 附件新增
     * @param annexReqs 附件信息
     * @param id 入库id
     * @param operator 操作人
     * @param operatorNo 操作人编码
     * @return 是否新增成功(true:成功 false:失败 )
     */
    private boolean addAnnex(List<AnnexReq> annexReqs, Integer id, String operator, String operatorNo) {
        try {
            //没有附件,将该id关联的所有附件设为无效
            if(CollectionUtils.isEmpty(annexReqs)){
                AnnexEntity annexReq = new AnnexEntity();
                annexReq.setParentId(id);
                annexReq.setModuleId(ModuleTypeEnum.WAREHOUSE_PLAN_IN_STOCK.getId());
                List<AnnexEntity> annexList = annexService.queryAll(annexReq);
                if(!CollectionUtils.isEmpty(annexList)){
                    for(AnnexEntity annex : annexList){
                        AnnexEntity updateAnnex= new AnnexEntity();
                        updateAnnex.setId(annex.getId());
                        //将被删除的附件设为失效
                        updateAnnex.setValid(DataIsValidEnum.INVALID.getId());
                        annexService.update(updateAnnex);
                    }
                }
                return true;
            }
            //存在附件,新增附件信息
            List<AnnexEntity> list = new ArrayList<>();
            //获取旧的附件id集合
            List<Integer> oldIds = new ArrayList<>();
            for(AnnexReq annexReq : annexReqs){
                if(null != annexReq.getNews()){
                    //属于旧附件 只取id,不新增
                    oldIds.add(annexReq.getId());
                    continue;
                }
                AnnexEntity annex = new AnnexEntity();
                BeanUtils.copyProperties(annexReq, annex);
                //设置关联模块id
                annex.setModuleId(ModuleTypeEnum.WAREHOUSE_PLAN_IN_STOCK.getId());
                //设置关联模块父id
                annex.setParentId(id);
                //设置上传时间
                annex.setUploadTime(DateUtils.convertStringToDate(annexReq.getUploadTime(), DateUtils.DATE_TIME_PATTERN));
                //设置修改时间
                annex.setUpdateTime(new Date());
                //设置操作人
                annex.setOperator(operator);
                //设置操作人编码
                annex.setOperatorNo(operatorNo);
                //设置数据有效
                annex.setValid(1);

                list.add(annex);
            }
            if(oldIds.size() > 0){
                //通过调拨id获取修改附件信息
                AnnexEntity annex = new AnnexEntity();
                annex.setModuleId(ModuleTypeEnum.WAREHOUSE_PLAN_IN_STOCK.getId());
                annex.setParentId(id);
                //获取上次附件信息
                List<AnnexEntity> annexList = annexService.queryAll(annex);
                if(!CollectionUtils.isEmpty(annexList)){
                    //获取上次附件id集合
                    List<Integer> oldAnnexIds = annexList.stream().map(p -> p.getId()).collect(Collectors.toList());
                    //得到被删除的附件id
                    Collection collection = new ArrayList(oldAnnexIds);
                    collection.removeAll(oldIds);
                    if(collection.size() > 0){
                        Iterator<Integer> it = collection.iterator();
                        while (it.hasNext()){
                            int detailId = it.next();
                            AnnexEntity annexEntity = new AnnexEntity();
                            annexEntity.setId(detailId);
                            //将被删除的附件设为失效
                            annexEntity.setValid(DataIsValidEnum.INVALID.getId());

                            annexService.update(annexEntity);
                        }
                    }
                }
            }
            if(!CollectionUtils.isEmpty(list)){
                //附件批量新增
                int res = annexService.batchInsert(list);
                if(res == list.size()){
                    return true;
                }
            }
            return true;
        }catch (Exception e){
            throw new RuntimeException();
        }
    }


    /**
     * 备货入库明细新增以及更新出运明细剩余数量
     * @param req 入参
     * @param id 出库id
     * @param creator 创建人
     * @param createNo 创建人编码
     */
    public void insertDetail(PlanInStoreReq req, Integer id, String creator, String createNo){
        if(!CollectionUtils.isEmpty(req.getDetails())){
            //获取修改明细id集合
            List<Integer> newIds = new ArrayList<>();
            //新增明细集合
            List<PlanInstoreProductEntity> addDetails = new ArrayList<>();
            for(AddPlanInStoreProductReq detailReq : req.getDetails()){
                //初始化明细对象
                PlanInstoreProductEntity detail = new PlanInstoreProductEntity();
                //赋值
                BeanUtils.copyProperties(detailReq, detail);
                //设置id
                detail.setInstoreId(id);
                //分摊费用单价
                BigDecimal shareCostPrice = detailReq.getShareCostPrice();
                //成本单价（入库成本）
                BigDecimal costUnitPrice = detailReq.getInstoreCost();
                //获取入库数量
                BigDecimal num = detailReq.getNum();
                //设置金额小计 = (分摊费用单价 + 成本单价)*入库数量
                BigDecimal cost = shareCostPrice.add(costUnitPrice);
                detail.setMoneySubtotal(cost.multiply(num));
                //获取托盘入数
                BigDecimal trayNumber = detailReq.getTrayNumber();
                if(StringUtil.isNotEmpty(trayNumber)){
                    //设置总托盘 = 入库数量除以托盘入数
                    detail.setTotalTray(num.divide(trayNumber, 2, BigDecimal.ROUND_HALF_UP));
                }
                //设置数据有效性(0:无效 1:有效)
                detail.setValid(DataIsValidEnum.VALID.getId());
                //创建时间
                detail.setCreateTime(new Date());

                //库存明细新增
                int stockDetailId = addStockDetail(detailReq, req.getBillNo(), creator, createNo);

                //更新出运明细产品剩余数量
                //updateCarryDetailLastNum(detailReq.getCarryDetailProductId(), detailReq.getNum(), 1);

                if(null == detailReq.getId()){
                    //新增

                    //设置明细库存id
                    detail.setStockDetailId(stockDetailId);
                    //设置出运明细产品id
                    //detail.setCarryDetailId(detailReq.getCarryDetailProductId());
                    addDetails.add(detail);
                }else {
                    //修改

                    //获取明细id
                    newIds.add(detailReq.getId());
                    detail.setModifyTime(new Date());
                    planInstoreProductService.update(detail);
                }

            }

            //处理被删除的入库明细
            handleBeenDeletedTransferDetail(req, id, newIds);

            if(!CollectionUtils.isEmpty(addDetails)){
                //调用接口保存入库明细
                planInstoreProductService.addList(addDetails);
            }
        }
    }

    /**
     * 处理被删除的入库明细
     * @param req 入库明细
     * @param id 入库id
     * @param newIds 修改后未被删除的入库明细id集合
     */
    private void handleBeenDeletedTransferDetail(PlanInStoreReq req, int id, List<Integer> newIds){
        if(null != req.getId()){
            //修改-找出被删除的入库明细

            PlanInstoreProductEntity planInStoreProductReq = new PlanInstoreProductEntity();
            //设置入库id
            planInStoreProductReq.setInstoreId(id);
            //查询有效数据
            planInStoreProductReq.setValid(DataIsValidEnum.VALID.getId());
            //调用接口查询结果
            List<PlanInstoreProductEntity> details = planInstoreProductService.queryAll(planInStoreProductReq);
            if(!CollectionUtils.isEmpty(details)){
                //获取出库明细id和库存明细id
                Map<String, Map<Integer, Integer>> stockIdAndStockDetailIdMap = getStockIdAndStockDetailIdMap(details);
                //获取出库数量
                Map<Integer, BigDecimal> outStockQuantityMap = getOutStockQuantityMap(details);
                //获取id集合
                List<Integer> oldIds = details.stream().map(p -> p.getId()).collect(Collectors.toList());
                //找出被删除的id
                Collection collection = new ArrayList(oldIds);
                collection.removeAll(newIds);
                if(collection.size() > 0){
                    //遍历删除被删除的明细
                    Iterator<Integer> ids = collection.iterator();
                    while (ids.hasNext()){
                        int deletedId = ids.next();
                        Integer stockId = stockIdAndStockDetailIdMap.get("stockIdMap").get(deletedId);
                        //获取库存数据
                        StockEntity stock = stockService.getStockById(stockId);
                        //初始化库存对象
                        StockEntity stockReq = new StockEntity();
                        //设置修改主键
                        stockReq.setId(stockId);
                        //获取出库数量
                        BigDecimal outStockQuantity = outStockQuantityMap.get(deletedId);
                        //回退出运明细产品的剩余数量
                        updateCarryDetailLastNum(deletedId, outStockQuantity, 2);
                        if(null != req.getStatus() && req.getStatus().equals(OperationStatusEnum.APPROVED_BOX.getId())){
                            //如果删除的是已批数据,则需要回退 实际数量、实际可用数量、可申请数量
                            stockReq.setRealQuantity(stock.getRealQuantity().subtract(outStockQuantity));
                            stockReq.setRealAvailableQuantity(stock.getRealAvailableQuantity().subtract(outStockQuantity));
                            stockReq.setCanApplyQuantity(stock.getCanApplyQuantity().subtract(outStockQuantity));
                        }
                        //回退删除的出库数量
                        stockService.update(stockReq);

                        PlanInstoreProductEntity detail = new PlanInstoreProductEntity();
                        detail.setId(deletedId);
                        detail.setValid(DataIsValidEnum.INVALID.getId());
                        //将删除的出库明细设为无效
                        planInstoreProductService.update(detail);
                        //通过出库明细id获取库存库存明细id
                        Integer stockDetailId = stockIdAndStockDetailIdMap.get("stockDetailIdMap").get(deletedId);
                        //将库存明细设为无效
                        StockDetailEntity stockDetail = new StockDetailEntity();
                        stockDetail.setId(stockDetailId);
                        stockDetail.setValid(DataIsValidEnum.INVALID.getId());
                        stockDetailService.update(stockDetail);
                    }
                }
            }
        }
    }

    /**
     * 获取入库数量
     * @param otherOutStockDetails 入库明细对象
     * @return key为出库明细id value为入库数量
     */
    private Map<Integer, BigDecimal> getOutStockQuantityMap(List<PlanInstoreProductEntity> otherOutStockDetails){
        //调拨数量
        Map<Integer, BigDecimal> outStockQuantityMap = new HashMap<>(otherOutStockDetails.size());
        for(PlanInstoreProductEntity otherOutStockDetail : otherOutStockDetails){
            outStockQuantityMap.put(otherOutStockDetail.getId(), otherOutStockDetail.getNum());
        }
        return outStockQuantityMap;
    }

    /**
     * 获取库存id和库存明细id
     * @param otherOutStockDetails 出库明细对象
     * @return key为调拨明细id value为库存id和库存明细id
     */
    private Map<String, Map<Integer, Integer>> getStockIdAndStockDetailIdMap(List<PlanInstoreProductEntity> otherOutStockDetails){
        //获取集合大小
        int size = otherOutStockDetails.size();
        //库存明细id
        Map<Integer, Integer> stockDetailIdMap = new HashMap<>(size);
        //库存id
        Map<Integer, Integer> stockIdMap = new HashMap<>(size);
        for(PlanInstoreProductEntity otherOutStockDetail : otherOutStockDetails){
            stockDetailIdMap.put(otherOutStockDetail.getId(), otherOutStockDetail.getStockDetailId());
            stockIdMap.put(otherOutStockDetail.getId(), otherOutStockDetail.getStockId());
        }
        Map<String, Map<Integer, Integer>> map = new HashMap<>(3);
        map.put("stockDetailIdMap", stockDetailIdMap);
        map.put("stockIdMap", stockIdMap);
        return map;
    }

    /**
     * 更新出运明细产品剩余数量
     * @param id 出运明细产品id
     * @param num 入库数量
     * @param type 1：剩余数量-入库数量 2：剩余数量+入库数量
     */
    private void updateCarryDetailLastNum(Integer id, BigDecimal num, int type){
        CarryDetailProductEntity detail = carryDetailProductService.queryById(id);
        if(null == detail || null == detail.getId()){
            return;
        }
        CarryDetailProductEntity updateReq = new CarryDetailProductEntity();
        updateReq.setId(id);
        //设置剩余数量
        BigDecimal lastAmount = new BigDecimal("0");
        if(StringUtil.isNotEmpty(detail.getLastAmount())){
            lastAmount = detail.getLastAmount();
        }
        if(1 == type) {
            updateReq.setLastAmount(lastAmount.subtract(num));
        }else if(2 == type){
            updateReq.setLastAmount(lastAmount.add(num));
        }
        carryDetailProductService.update(updateReq);
    }

    /**
     * 新增库存明细
     * @param detailReq 入库明细
     * @param billNo 单号
     * @param creator 创建人
     * @param createNo 创建人编码
     */
    private int addStockDetail(AddPlanInStoreProductReq detailReq, String billNo, String creator, String createNo){
        //初始化库存明细对象
        StockDetailEntity stockDetail = new StockDetailEntity();
        //赋值
        BeanUtils.copyProperties(detailReq, stockDetail);
        //设置标题
        stockDetail.setTitle(DataSourceTitleEnum.PLAN_IN_STORE.getDesc());
        //设置单据编号
        stockDetail.setInvoiceNumber(billNo);
        //设置单价
        stockDetail.setUnitPrice(detailReq.getInstoreCost());
        //设置数量
        stockDetail.setQuantity(detailReq.getNum());
        //设置模块id
        stockDetail.setModuleId(ModuleTypeEnum.WAREHOUSE_PLAN_IN_STOCK.getId());
        //设置创建人
        stockDetail.setInStorePerson(creator);
        //设置创建人编码
        stockDetail.setInStoreCode(createNo);
        //设置操作人
        stockDetail.setOperator(creator);
        //设置操作人编码
        stockDetail.setOperationCode(createNo);
        if(null == detailReq.getId()){
            //新增

            //设置创建时间
            stockDetail.setCreateDate(new Date());
            //设置有效性
            stockDetail.setValid(DataIsValidEnum.VALID.getId());
            stockDetailService.insert(stockDetail);

        }else {
            //修改

            stockDetail.setId(detailReq.getStockDetailId());
            stockDetailService.update(stockDetail);
        }

        return stockDetail.getId();
    }

    /**
     * 备货入库新增、修改
     * @param req 参数实体
     * @param creator 创建人
     * @param createNo 创建人编码
     * @return 新增、修改结果
     */
    private Integer addOrUpdatePlanInStore(PlanInStoreReq req, String creator, String createNo){
        //初始化对象
        PlanInstoreEntity planInStore = new PlanInstoreEntity();
        //赋值
        BeanUtils.copyProperties(req, planInStore);
        //设置日期
        planInStore.setTime(new Date());
        //设置创建人
        planInStore.setOperator(creator);
        //设置创建人编码
        planInStore.setOperationNo(createNo);
        //设置状态,默认为草稿箱
        planInStore.setStatus(OperationStatusEnum.DRAFT_BOX.getId());

        if(null == req.getId()){
            //新增
            //创建日期
            planInStore.setCreateTime(new Date());
            //设置有效性
            planInStore.setValid(DataIsValidEnum.VALID.getId());
            //调用接口新增
            planInstoreService.insert(planInStore);
        }else {
            //修改
            //修改时间
            planInStore.setModifyTime(new Date());
            planInstoreService.update(planInStore);
        }
        return planInStore.getId();
    }

    /**
     * 校验入库数量是否小于等于参考数量（true:是 false:否）
     * @param list 入库明细集合
     * @return boolean
     */
    private boolean checkInStockQuantity(List<AddPlanInStoreProductReq> list){
        for(AddPlanInStoreProductReq detailReq : list){
            //参考数量
            BigDecimal referenceQuantity = detailReq.getReferenceQuantity();
            //入库数量必须小于等于实际数量
            boolean flag = detailReq.getNum().compareTo(referenceQuantity) < 1;
            if(!flag){
                return false;
            }
        }
        return true;
    }


    /**
     * 校验单号是否存在
     * @param billNo 单号
     * @return true:不重复 false:重复
     */
    private boolean checkRepeatBillNo(String billNo){
        PlanInstoreEntity req = new PlanInstoreEntity();
        req.setBillNo(billNo);
        List<PlanInstoreEntity> list = planInstoreService.queryAll(req);
        if(CollectionUtils.isEmpty(list)){
            return true;
        }
        return false;
    }

    /**
     * 获取备货入库详情
     * @param id 入库id
     * @param flag true:修改 false:详情
     * @return
     */
    public PlanInStoreDetailVo getDetailInfo(Integer id, boolean flag){
        //初始化回参实体
        PlanInStoreDetailVo vo = new PlanInStoreDetailVo();
        if(null == id){
            return vo;
        }

        //第一步：获取主表信息
        PlanInstoreEntity planInStore = planInstoreService.queryById(id);
        if(null == planInStore || null == planInStore.getId()){
            return vo;
        }
        //赋值
        BeanUtils.copyProperties(planInStore, vo);
        //设置入库时间
        vo.setTime(DateUtils.format(planInStore.getTime(), DateUtils.DATE_PATTERN));
        //设置创建时间
        vo.setCreateTime(DateUtils.format(planInStore.getCreateTime(), DateUtils.DATE_PATTERN));

        //第二步：获取对应产品信息
        PlanInstoreProductEntity detailReq = new PlanInstoreProductEntity();
        //设置入库id
        detailReq.setInstoreId(id);
        //设置数据为有效
        detailReq.setValid(DataIsValidEnum.VALID.getId());
        List<PlanInstoreProductEntity> details = planInstoreProductService.queryAll(detailReq);

        if(!CollectionUtils.isEmpty(details)){
            List<PlanInStoreProductVo> productVos = details.stream().map(p -> {
                PlanInStoreProductVo productVo = new PlanInStoreProductVo();
                //赋值
                BeanUtils.copyProperties(p, productVo);

                //设置和同类型
                productVo.setContractTypeStr(ContractTypeEnum.getDescById(p.getContractType()));

                if(flag){
                    //根据id获取最新剩余数量
                    //CarryDetailProductEntity productEntity = carryDetailProductService.getCarryDetailProductById(p.getCarryDetailId());
                    //productVo.setReferenceQuantity(productEntity.getLastAmount());
                }
                return productVo;
            }).collect(Collectors.toList());

            vo.setDetailList(productVos);
        }

        //第三步：获取附件信息
        AnnexEntity annex = new AnnexEntity();
        annex.setModuleId(ModuleTypeEnum.WAREHOUSE_PLAN_IN_STOCK.getId());
        annex.setParentId(id);
        //设置数据有效
        annex.setValid(DataIsValidEnum.VALID.getId());
        List<AnnexEntity> annexList = annexService.queryAll(annex);
        if(!CollectionUtils.isEmpty(annexList)){
            List<AnnexVo> annexVos = annexList.stream().map(p -> {
                AnnexVo annexVo = new AnnexVo();
                //赋值
                BeanUtils.copyProperties(p, annexVo);
                //上传时间转换
                annexVo.setUploadTime(DateUtils.format(p.getUploadTime(), DateUtils.DATE_TIME_PATTERN));
                //设置附件为旧附件,用以区分修改时附件状态
                annexVo.setNews(0);

                return annexVo;
            }).collect(Collectors.toList());

            vo.setAnnexVos(annexVos);
        }
        return vo;
    }

    /**
     * 删除(修改数据有效性)
     * @param id id
     * @param status 状态(1.草稿箱 2.待批箱 3.已批箱 4.完成箱 5.垃圾箱)
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id, Integer status){
        if(null == id){
            return;
        }
        PlanInstoreEntity planInStoreReq = new PlanInstoreEntity();
        planInStoreReq.setId(id);
        if(OperationStatusEnum.DRAFT_BOX.getId() == status){
            //草稿箱删除：数据设为垃圾箱
            planInStoreReq.setStatus(OperationStatusEnum.TRASH_CAN.getId());
            planInstoreService.update(planInStoreReq);
            return;
        }else if(OperationStatusEnum.TRASH_CAN.getId() == status){
            //垃圾箱删除：数据设为无效
            planInStoreReq.setValid(DataIsValidEnum.INVALID.getId());
            planInstoreService.update(planInStoreReq);
        }
        //获取明细数据
        PlanInstoreProductEntity detailReq = new PlanInstoreProductEntity();
        detailReq.setInstoreId(id);
        detailReq.setValid(DataIsValidEnum.VALID.getId());
        //获取明细
        List<PlanInstoreProductEntity> inventoryDetails = planInstoreProductService.queryAll(detailReq);
        if(CollectionUtils.isEmpty(inventoryDetails)){
            //没有明细,只删除主表数据
            return;
        }
        for(PlanInstoreProductEntity detail : inventoryDetails){
            //数量不为空
            if(StringUtil.isNotEmpty(detail.getNum())){
                //出运明细剩余数量修改
                StockDetailEntity stockDetail = new StockDetailEntity();
                stockDetail.setId(detail.getStockDetailId());

                //明细修改
                PlanInstoreProductEntity planInStoreProduct = new PlanInstoreProductEntity();
                planInStoreProduct.setId(detail.getId());

                if(OperationStatusEnum.TRASH_CAN.getId() == status){
                    //垃圾箱删除：数据设为无效
                    //将明细设为失效
                    planInStoreProduct.setValid(DataIsValidEnum.INVALID.getId());
                    stockDetail.setValid(DataIsValidEnum.INVALID.getId());
                }
                //修改库存明细状态
                stockDetailService.update(stockDetail);
                //修改明细状态
                planInstoreProductService.update(planInStoreProduct);
            }
        }
        return;
    }

    /**
     * 数据操作接口
     * @param req 操作类型
     * 1.提交审批 2.审批通过 3.审批退回 4.完成 5.还原
     * 箱体：1.草稿箱 2.待批箱 3.已批箱 4.完成箱 5.垃圾箱
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public R operation(OperationReq req){
        if(null == req.getId() || null == req.getOperation()){
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }
        PlanInstoreEntity planInStore = new PlanInstoreEntity();
        //设置id
        planInStore.setId(req.getId());
        if(req.getOperation() == SubmitStatusEnum.SUBMIT_APPROVE.getId()){
            //提交审批后,状态直接为已批箱
            approved(req.getId());
            planInStore.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
        }else if(req.getOperation() == SubmitStatusEnum.APPROVE_SUCCESS.getId()){
            //审批通过,库存存在同一批数据：累加，否则库存新增
            approved(req.getId());
            planInStore.setStatus(OperationStatusEnum.APPROVED_BOX.getId());
        }else if(req.getOperation() == SubmitStatusEnum.APPROVE_RETURN.getId()){
            //审批退回后只修改调拨状态
            //状态设为草稿箱
            planInStore.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
        }else if(req.getOperation() == SubmitStatusEnum.SUCCESS.getId()){
            //将状态设为完成
            planInStore.setStatus(OperationStatusEnum.COMPLETION_BOX.getId());
        }else if(req.getOperation() == SubmitStatusEnum.REDUCTION.getId()){
            //将状态改为草稿箱
            planInStore.setStatus(OperationStatusEnum.DRAFT_BOX.getId());
        }
        //修改数据
        planInstoreService.update(planInStore);
        return R.build("");
    }

    /**
     * 审批
     * @param id
     */
    private void approved(Integer id){
        //获取主表信息
        PlanInstoreEntity planInStore = planInstoreService.queryById(id);
        //初始化查询参数对象
        PlanInstoreProductEntity detailReq = new PlanInstoreProductEntity();
        detailReq.setInstoreId(id);
        detailReq.setValid(DataIsValidEnum.VALID.getId());
        List<PlanInstoreProductEntity> detailList = planInstoreProductService.queryAll(detailReq);
        if(CollectionUtils.isEmpty(detailList)){
            return;
        }
        for(PlanInstoreProductEntity detail : detailList){
            //获取库存信息
            StockEntity stockReq = new StockEntity();
            stockReq.setLotNo(detail.getLotNo());
            stockReq.setProductCode(detail.getProductCode());
            stockReq.setSpecificationCode(detail.getSpecificationCode());
            stockReq.setWarehouseCode(detail.getNewWarehouseId());
            //根据库存id获取库存信息
            List<StockEntity> stockList = stockService.getTheSameStockInfo(stockReq);
            //同一批次，产品编码  规格编码，仓库id  合同号 如果都相同 则为同一组
            StockEntity stock = new StockEntity();
            //数量
            BigDecimal num = detail.getNum();
            if(CollectionUtils.isEmpty(stockList)){
                //不存在同一类型数据 新增
                BeanUtils.copyProperties(detail, stock);
                //创建时间
                stock.setCreateDate(new Date());
                //入库单号
                stock.setInStoreBillNo(planInStore.getBillNo());
                //实际数量
                stock.setRealQuantity(num);
                //实际可用数量
                stock.setRealAvailableQuantity(num);
                //可申请数量
                stock.setCanApplyQuantity(num);
                //调拨申请数量
                stock.setTransferApplyQuantity(new BigDecimal("0"));
                //出库申请数量
                stock.setOutWarehouseApply(new BigDecimal("0"));
                //入库人
                stock.setSalesman(planInStore.getPerson());
                //入库人编码
                stock.setSalesmanCode(planInStore.getPersonNo());
                //产品类型
                stock.setProductType(detail.getContractType());
                //仓库编码
                stock.setWarehouseCode(detail.getNewWarehouseId());
                //仓库名称
                stock.setWarehouseName(detail.getNewWarehouseName());
                //合同号为空
                stock.setContractNo("");
                //和同类型待定
                stock.setContractType(ContractTypeEnum.TO_BE_DETERMINED.getId());
                //成本单价=入库成本
                stock.setProductUnitPrice(detail.getInstoreCost());
                //成本金额小计
                stock.setCostAmount(detail.getMoneySubtotal());
                //入库日期=产品创建日期
                stock.setInStoreDate(detail.getCreateTime());

                stockService.insert(stock);
            }else{
                StockEntity stockInfo = stockList.get(0);
                //存在同一类型数据 累加
                stock.setId(stockInfo.getId());
                //实际数量
                BigDecimal realQuantity = new BigDecimal("0");
                if(StringUtil.isNotEmpty(stockInfo.getRealQuantity())){
                    realQuantity = stockInfo.getRealQuantity();
                }
                stock.setRealQuantity(realQuantity.add(num));
                //实际可用数量
                BigDecimal realAvailableQuantity = new BigDecimal("0");
                if(StringUtil.isNotEmpty(stockInfo.getRealAvailableQuantity())){
                    realAvailableQuantity = stockInfo.getRealAvailableQuantity();
                }
                stock.setRealAvailableQuantity(realAvailableQuantity.add(num));
                //可申请数量
                BigDecimal canApplyQuantity = new BigDecimal("0");
                if(StringUtil.isNotEmpty(stockInfo.getCanApplyQuantity())){
                    canApplyQuantity = stockInfo.getCanApplyQuantity();
                }
                stock.setCanApplyQuantity(canApplyQuantity.add(num));

                //和同类型待定
                stock.setContractType(ContractTypeEnum.TO_BE_DETERMINED.getId());

                //成本金额小计:实际数量*成本单价
                BigDecimal costAmount = realQuantity.multiply(stockInfo.getProductUnitPrice());
                stock.setCostAmount(costAmount);

                //调用接口进行修改
                stockService.update(stock);
            }

        }
    }






    //**************************入库通知统计********************************************
    /**
     * 获取String类型不为空数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private String getNotNullOfStringInfo(String value){
        if(StringUtils.isEmpty(value)){
            return "";
        }else {
            return value;
        }
    }

    /**
     * 获取BigDecimal类型不为空的数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private BigDecimal getNotNullOfBigDecimalInfo(BigDecimal value){
        if(StringUtil.isNotEmpty(value)){
            return value;
        }else {
            return new BigDecimal("0");
        }
    }
    /**
     * 入库通知统计-集合
     * @param req
     * @return
     */
    private List<PlanInStoreStatistics1Rsp> planInStoreStatistics1RspList(PlanInStoreStatistics1Req req){
        List<PlanInStoreStatistics1Rsp> planInStoreStatistics1RspList=planInstoreService.planInStoreStatistics1ListByPage(req);
        for (PlanInStoreStatistics1Rsp p:planInStoreStatistics1RspList) {
            p.setTimeStr(DateUtils.format(p.getTime(),DateUtils.DATE_PATTERN));
            p.setCreateTimeStr(DateUtils.format(p.getCreateTime(),DateUtils.DATE_PATTERN));
            p.setCarryDetailTimeStr(DateUtils.format(p.getCarryDetailTime(),DateUtils.DATE_PATTERN));
            if (StringUtils.isNotEmpty(p.getProductType())){
                switch (p.getProductType()){
                    case "1" :
                        p.setProductType("成品") ;
                        break;
                    case "2" :
                        p.setProductType("配件");
                        break;
                }
            }

        }
        return planInStoreStatistics1RspList;
    }
    /**
     * 入库通知统计-分页
     * @param req
     * @return
     */
    public PageInfo<PlanInStoreStatistics1Rsp> planInStoreStatistics1ListByPage(PlanInStoreStatistics1Req req) {
        List<PlanInStoreStatistics1Rsp> planInStoreStatistics1RspList=planInStoreStatistics1RspList(req);
        PageInfo<PlanInStoreStatistics1Rsp> pageInfo=new PageInfo(planInStoreStatistics1RspList);
        return pageInfo;
    }

    /**
     * 入库通知统计-导出
     * @return
     */
    public JSONObject planInStoreStatistics1Export(PlanInStoreStatistics1Req req){
        List<PlanInStoreStatistics1Rsp> planInStoreStatistics1RspList=planInStoreStatistics1RspList(req);
        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitlePlanInStore();
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(planInStoreStatistics1RspList)){
            obj.put("data", data);
            return obj;
        }
        excelPlanInStoreExport(data,planInStoreStatistics1RspList);
        obj.put("data", data);
        return obj;
    }
    public JSONArray getTitlePlanInStore(){
        JSONArray obj=new JSONArray();
        obj.add("序号");
        obj.add("通知单号");
        obj.add("创建日期");
        obj.add("送仓日期");
        obj.add("出运日期");
        obj.add("产品编码");
        obj.add("规格编码");
        obj.add("规格说明");
        obj.add("中文名称");
        obj.add("批次");
        obj.add("通知数量");
        obj.add("产品类型");
        obj.add("其他.采购单号");
        obj.add("供应商");


        obj.add("成本单价");
        obj.add("成本小计");
        obj.add("配件成本");
        obj.add("成品成本");
        obj.add("采购单价");
        obj.add("采购成本单价");
        obj.add("配件成本");
        obj.add("配件供应商");
        obj.add("配件采购单号");
        return obj;
    }
    public void excelPlanInStoreExport(JSONArray data,List<PlanInStoreStatistics1Rsp> list ){
        //通知数量
        Integer num = 0;
        BigDecimal costSubtotal=new BigDecimal(0);
        Integer i=0;
        for (PlanInStoreStatistics1Rsp vo: list) {
            JSONArray infoList = new JSONArray();
            infoList.add(++i);
            infoList.add(getNotNullOfStringInfo(vo.getBillNo()));
            infoList.add(getNotNullOfStringInfo(vo.getCreateTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getCarryDetailTimeStr()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationExplanation()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCname()));
            infoList.add(getNotNullOfStringInfo(vo.getLotNo()));
            infoList.add(vo.getNum());
            infoList.add(getNotNullOfStringInfo(vo.getProductType()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseNo()));
            infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));

            infoList.add(getNotNullOfStringInfo(vo.getCostUnitPrice()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCostSubtotal()));
            infoList.add(getNotNullOfStringInfo(vo.getAccessoriesCost()));
            infoList.add(getNotNullOfStringInfo(vo.getFinishedProductCost()));
            infoList.add(getNotNullOfStringInfo(vo.getPrice()));
            infoList.add(getNotNullOfStringInfo(vo.getCostPrice()));
            infoList.add(getNotNullOfStringInfo(vo.getPartsCostUnitPrice()));
            infoList.add(getNotNullOfStringInfo(vo.getPartsSupplierName()));
            infoList.add(getNotNullOfStringInfo(vo.getPartsPurchaseNo()));

            if(vo.getNum()!=null){
                num = num+vo.getNum();
            }
            if(vo.getCostSubtotal()!=null){
                costSubtotal = costSubtotal.add(vo.getCostSubtotal());
            }
            data.add(infoList);
        }
        //合计
        JSONArray infoList = new JSONArray();
        infoList.add("合计");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add(num);
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add(costSubtotal);
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");
        infoList.add("");

        data.add(infoList);
    }


}
